home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / nasm095s.zip / OUTRDF.C < prev    next >
C/C++ Source or Header  |  1997-07-27  |  13KB  |  501 lines

  1. /* outrdf.c    output routines for the Netwide Assembler to produce
  2.  *        RDOFF format object files (which are intended mainly
  3.  *        for use in proprietary projects, as the code to load and
  4.  *        execute them is very simple). They will also be used
  5.  *        for device drivers and possibly some executable files
  6.  *        in the MOSCOW operating system. See Rdoff.txt for
  7.  *        details.
  8.  *
  9.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  10.  * Julian Hall. All rights reserved. The software is
  11.  * redistributable under the licence given in the file "Licence"
  12.  * distributed in the NASM archive.
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19. #include <assert.h>
  20.  
  21. #include "nasm.h"
  22. #include "nasmlib.h"
  23. #include "outform.h"
  24.  
  25. /* VERBOSE_WARNINGS: define this to add some extra warnings... */
  26. #define VERBOSE_WARNINGS     
  27.  
  28. #ifdef OF_RDF
  29.  
  30. typedef short int16;    /* not sure if this will be required to be altered
  31.                at all... best to typedef it just in case */
  32.  
  33. static const char *RDOFFId = "RDOFF1";    /* written to start of RDOFF files */
  34.  
  35. /* the records that can be found in the RDOFF header */
  36.  
  37. /* Note that whenever a segment is referred to in the RDOFF file, its number
  38.  * is always half of the segment number that NASM uses to refer to it; this
  39.  * is because NASM only allocates even numbered segments, so as to not
  40.  * waste any of the 16 bits of segment number written to the file - this
  41.  * allows up to 65533 external labels to be defined; otherwise it would be
  42.  * 32764. */
  43.  
  44. struct RelocRec {
  45.   char    type;        /* must be 1 */
  46.   char    segment;    /* only 0 for code, or 1 for data supported,
  47.              * but add 64 for relative refs (ie do not require
  48.              * reloc @ loadtime, only linkage) */
  49.   long    offset;        /* from start of segment in which reference is loc'd */
  50.   char    length;        /* 1 2 or 4 bytes */
  51.   int16    refseg;        /* segment to which reference refers to */
  52. };
  53.  
  54. struct ImportRec {
  55.   char     type;        /* must be 2 */
  56.   int16    segment;    /* segment number allocated to the label for reloc
  57.              * records - label is assumed to be at offset zero
  58.              * in this segment, so linker must fix up with offset
  59.              * of segment and of offset within segment */
  60.   char    label[33];    /* zero terminated... should be written to file until
  61.              * the zero, but not after it - max len = 32 chars */
  62. };
  63.  
  64. struct ExportRec {
  65.   char    type;        /* must be 3 */
  66.   char    segment;    /* segment referred to (0/1) */
  67.   long    offset;        /* offset within segment */
  68.   char    label[33];    /* zero terminated as above. max len = 32 chars */
  69. };
  70.  
  71. struct DLLRec {
  72.   char    type;        /* must be 4 */
  73.   char    libname[128];    /* name of library to link with at load time */
  74. };
  75.  
  76. struct BSSRec {
  77.   char    type;        /* must be 5 */
  78.   long    amount;        /* number of bytes BSS to reserve */
  79. };
  80.  
  81. /* code for managing buffers needed to seperate code and data into individual
  82.  * sections until they are ready to be written to the file.
  83.  * We'd better hope that it all fits in memory else we're buggered... */
  84.  
  85. #define BUF_BLOCK_LEN 4088        /* selected to match page size (4096)
  86.                                          * on 80x86 machines for efficiency */
  87.  
  88. typedef struct memorybuffer {
  89.   int length;
  90.   char buffer[BUF_BLOCK_LEN];
  91.   struct memorybuffer *next;
  92. } memorybuffer;
  93.  
  94. static memorybuffer * newmembuf(void){
  95.   memorybuffer * t;
  96.  
  97.   t = nasm_malloc(sizeof(memorybuffer));
  98.  
  99.   t->length = 0;
  100.   t->next = NULL;
  101.   return t;
  102. }
  103.  
  104. static void membufwrite(memorybuffer *b, void *data, int bytes) {
  105.   int16 w;
  106.   long l;
  107.  
  108.   if (b->next) {     /* memory buffer full - use next buffer */
  109.     membufwrite(b->next,data,bytes);
  110.     return;
  111.   }
  112.   if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
  113.       || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) {
  114.  
  115.     /* buffer full and no next allocated... allocate and initialise next
  116.      * buffer */
  117.  
  118.     b->next = newmembuf();
  119.     membufwrite(b->next,data,bytes);
  120.     return;
  121.   }
  122.  
  123.   switch(bytes) {
  124.   case -4:        /* convert to little-endian */
  125.     l = * (long *) data ;
  126.     b->buffer[b->length++] = l & 0xFF;
  127.     l >>= 8 ;
  128.     b->buffer[b->length++] = l & 0xFF;
  129.     l >>= 8 ;
  130.     b->buffer[b->length++] = l & 0xFF;
  131.     l >>= 8 ;
  132.     b->buffer[b->length++] = l & 0xFF;
  133.     break;
  134.  
  135.   case -2:
  136.     w = * (int16 *) data ;
  137.     b->buffer[b->length++] = w & 0xFF;
  138.     w >>= 8 ;
  139.     b->buffer[b->length++] = w & 0xFF;
  140.     break;
  141.  
  142.   default:
  143.     while(bytes--) {
  144.       b->buffer[b->length++] = *(* (unsigned char **) &data);
  145.  
  146.       (* (unsigned char **) &data)++ ;
  147.     }
  148.     break;
  149.   }
  150. }
  151.  
  152. static void membufdump(memorybuffer *b,FILE *fp)
  153. {
  154.   if (!b) return;
  155.  
  156.   fwrite (b->buffer, 1, b->length, fp);
  157.  
  158.   membufdump(b->next,fp);
  159. }
  160.  
  161. static int membuflength(memorybuffer *b)
  162. {
  163.   if (!b) return 0;
  164.   return b->length + membuflength(b->next);
  165. }
  166.  
  167. static void freemembuf(memorybuffer *b)
  168. {
  169.   if (!b) return;
  170.   freemembuf(b->next);
  171.   nasm_free(b);
  172. }
  173.  
  174. /***********************************************************************
  175.  * Actual code to deal with RDOFF ouput format begins here...
  176.  */
  177.  
  178. /* global variables set during the initialisation phase */
  179.  
  180. static memorybuffer *seg[2];    /* seg 0 = code, seg 1 = data */
  181. static memorybuffer *header;    /* relocation/import/export records */
  182.  
  183. static FILE *ofile;
  184.  
  185. static efunc error;
  186.  
  187. static int segtext,segdata,segbss;
  188. static long bsslength;
  189.  
  190. static void rdf_init(FILE *fp, efunc errfunc, ldfunc ldef)
  191. {
  192.   ofile = fp;
  193.   error = errfunc;
  194.   seg[0] = newmembuf();
  195.   seg[1] = newmembuf();
  196.   header = newmembuf();
  197.   segtext = seg_alloc();
  198.   segdata = seg_alloc();
  199.   segbss = seg_alloc();
  200.   if (segtext != 0 || segdata != 2 || segbss != 4)
  201.     error(ERR_PANIC,"rdf segment numbers not allocated as expected (%d,%d,%d)",
  202.       segtext,segdata,segbss);
  203.   bsslength=0;
  204. }
  205.  
  206. static long rdf_section_names(char *name, int pass, int *bits)
  207. {
  208.   /*
  209.    * Default is 32 bits.
  210.    */
  211.   if (!name)
  212.     *bits = 32;
  213.  
  214.   if (!name) return 0;
  215.   if (!strcmp(name, ".text"))        return 0;
  216.   else if (!strcmp(name, ".data"))    return 2;
  217.   else if (!strcmp(name, ".bss"))    return 4;
  218.   else
  219.     return NO_SEG;
  220. }
  221.  
  222. static void write_reloc_rec(struct RelocRec *r)
  223. {
  224.   r->refseg >>= 1;    /* adjust segment nos to RDF rather than NASM */
  225.  
  226.   membufwrite(header,&r->type,1);
  227.   membufwrite(header,&r->segment,1);
  228.   membufwrite(header,&r->offset,-4);
  229.   membufwrite(header,&r->length,1);
  230.   membufwrite(header,&r->refseg,-2);    /* 9 bytes written */
  231. }
  232.  
  233. static void write_export_rec(struct ExportRec *r)
  234. {
  235.   r->segment >>= 1;
  236.  
  237.   membufwrite(header,&r->type,1);
  238.   membufwrite(header,&r->segment,1);
  239.   membufwrite(header,&r->offset,-4);
  240.   membufwrite(header,r->label,strlen(r->label) + 1);
  241. }
  242.  
  243. static void write_import_rec(struct ImportRec *r)
  244. {
  245.   r->segment >>= 1;
  246.  
  247.   membufwrite(header,&r->type,1);
  248.   membufwrite(header,&r->segment,-2);
  249.   membufwrite(header,r->label,strlen(r->label) + 1);
  250. }
  251.  
  252. static void write_bss_rec(struct BSSRec *r)
  253. {
  254.     membufwrite(header,&r->type,1);
  255.     membufwrite(header,&r->amount,-4);
  256. }
  257.  
  258. static void write_dll_rec(struct DLLRec *r)
  259. {
  260.     membufwrite(header,&r->type,1);
  261.     membufwrite(header,r->libname,strlen(r->libname) + 1);
  262. }
  263.  
  264. static void rdf_deflabel(char *name, long segment, long offset, int is_global)
  265. {
  266.   struct ExportRec r;
  267.   struct ImportRec ri;
  268. #ifdef VERBOSE_WARNINGS
  269.   static int warned_common = 0;
  270. #endif
  271.  
  272.   if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
  273.     error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
  274.     return;
  275.   }
  276.  
  277.   if (is_global && segment > 4) {
  278. #ifdef VERBOSE_WARNINGS
  279.     if (! warned_common) {
  280.       error(ERR_WARNING,"common declarations not supported... using extern");
  281.       warned_common = 1;
  282.     }
  283. #endif
  284.     is_global = 0;
  285.   }
  286.  
  287.   if (is_global) {
  288.     r.type = 3;
  289.     r.segment = segment;
  290.     r.offset = offset;
  291.     strncpy(r.label,name,32);
  292.     r.label[32] = 0;
  293.     write_export_rec(&r);
  294.   }
  295.  
  296.   if (segment > 4) {   /* EXTERN declaration */
  297.     ri.type = 2;
  298.     ri.segment = segment;
  299.     strncpy(ri.label,name,32);
  300.     ri.label[32] = 0;
  301.     write_import_rec(&ri);
  302.   }
  303. }
  304.  
  305. static void rdf_out (long segto, void *data, unsigned long type,
  306.              long segment, long wrt)
  307. {
  308.   long bytes = type & OUT_SIZMASK;
  309.   struct RelocRec rr;
  310.   unsigned char databuf[4],*pd;
  311.  
  312.   segto >>= 1;    /* convert NASM segment no to RDF number */
  313.  
  314.   if (segto != 0 && segto != 1 && segto != 2) {
  315.     error(ERR_NONFATAL,"specified segment not supported by rdf output format");
  316.     return;
  317.   }
  318.  
  319.   if (wrt != NO_SEG) {
  320.     wrt = NO_SEG;               /* continue to do _something_ */
  321.     error (ERR_NONFATAL, "WRT not supported by rdf output format");
  322.   }
  323.  
  324.   type &= OUT_TYPMASK;
  325.  
  326.   if (segto == 2 && type != OUT_RESERVE)
  327.   {
  328.       error(ERR_NONFATAL, "BSS segments may not be initialised");
  329.  
  330.       /* just reserve the space for now... */
  331.  
  332.       if (type == OUT_REL2ADR)
  333.     bytes = 2;
  334.       else
  335.     bytes = 4;
  336.       type = OUT_RESERVE;
  337.   }
  338.  
  339.   if (type == OUT_RESERVE) {
  340.       if (segto == 2)        /* BSS segment space reserverd */
  341.       bsslength += bytes;
  342.       else
  343.     while (bytes --)
  344.         membufwrite(seg[segto],databuf,1);
  345.   }
  346.   else if (type == OUT_RAWDATA) {
  347.       if (segment != NO_SEG)
  348.       error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
  349.       membufwrite(seg[segto],data,bytes);
  350.   }
  351.   else if (type == OUT_ADDRESS) {
  352.  
  353.     /* if segment == NO_SEG then we are writing an address of an
  354.        object within the same segment - do not produce reloc rec. */
  355.  
  356.     if (segment != NO_SEG)
  357.     {
  358.  
  359.     /* it's an address, so we must write a relocation record */
  360.  
  361.     rr.type = 1;        /* type signature */
  362.     rr.segment = segto;        /* segment we're currently in */
  363.     rr.offset = membuflength(seg[segto]);    /* current offset */
  364.     rr.length = bytes;        /* length of reference */
  365.     rr.refseg = segment;    /* segment referred to */
  366.     write_reloc_rec(&rr);
  367.     }
  368.  
  369.     pd = databuf;    /* convert address to little-endian */
  370.     if (bytes == 2)
  371.       WRITESHORT (pd, *(long *)data);
  372.     else
  373.       WRITELONG (pd, *(long *)data);
  374.  
  375.     membufwrite(seg[segto],databuf,bytes);
  376.  
  377.   }
  378.   else if (type == OUT_REL2ADR)
  379.   {
  380.     if (segment == segto)
  381.       error(ERR_PANIC, "intra-segment OUT_REL2ADR");
  382.     if (segment != NO_SEG && segment % 2) {
  383.       error(ERR_NONFATAL, "rdf format does not support segment base refs");
  384.     }
  385.  
  386.     rr.type = 1;        /* type signature */
  387.     rr.segment = segto+64;    /* segment we're currently in + rel flag */
  388.     rr.offset = membuflength(seg[segto]);    /* current offset */
  389.     rr.length = 2;        /* length of reference */
  390.     rr.refseg = segment;    /* segment referred to */
  391.     write_reloc_rec(&rr);
  392.  
  393.     /* work out what to put in the code: offset of the end of this operand,
  394.      * subtracted from any data specified, so that loader can just add
  395.      * address of imported symbol onto it to get address relative to end of
  396.      * instruction: import_address + data(offset) - end_of_instrn */
  397.  
  398.     rr.offset = *(long *)data -(rr.offset + bytes);
  399.  
  400.     membufwrite(seg[segto],&rr.offset,-2);
  401.   }
  402.   else if (type == OUT_REL4ADR)
  403.   {
  404.     if (segment == segto)
  405.       error(ERR_PANIC, "intra-segment OUT_REL4ADR");
  406.     if (segment != NO_SEG && segment % 2) {
  407.       error(ERR_NONFATAL, "rdf format does not support segment base refs");
  408.     }
  409.  
  410.     rr.type = 1;        /* type signature */
  411.     rr.segment = segto+64;    /* segment we're currently in + rel tag */
  412.     rr.offset = membuflength(seg[segto]);    /* current offset */
  413.     rr.length = 4;        /* length of reference */
  414.     rr.refseg = segment;    /* segment referred to */
  415.     write_reloc_rec(&rr);
  416.  
  417.     rr.offset = *(long *)data -(rr.offset + bytes);
  418.     membufwrite(seg[segto],&rr.offset,-4);
  419.   }
  420. }
  421.  
  422. static void rdf_cleanup (void) {
  423.   long        l;
  424.   unsigned char b[4],*d;
  425.   struct BSSRec    bs;
  426.  
  427.  
  428.   /* should write imported & exported symbol declarations to header here */
  429.  
  430.   /* generate the output file... */
  431.   fwrite(RDOFFId,6,1,ofile);    /* file type magic number */
  432.  
  433.   if (bsslength != 0)        /* reserve BSS */
  434.   {
  435.       bs.type = 5;
  436.       bs.amount = bsslength;
  437.       write_bss_rec(&bs);
  438.   }
  439.  
  440.   l = membuflength(header);d=b;
  441.   WRITELONG(d,l);
  442.  
  443.   fwrite(b,4,1,ofile);        /* write length of header */
  444.   membufdump(header,ofile);    /* dump header */
  445.  
  446.   l = membuflength(seg[0]);d=b;    /* code segment */
  447.   WRITELONG(d,l);
  448.  
  449.   fwrite(b,4,1,ofile);
  450.   membufdump(seg[0],ofile);
  451.  
  452.   l = membuflength(seg[1]);d=b;    /* data segment */
  453.   WRITELONG(d,l);
  454.  
  455.   fwrite(b,4,1,ofile);
  456.   membufdump(seg[1],ofile);
  457.  
  458.   freemembuf(header);
  459.   freemembuf(seg[0]);
  460.   freemembuf(seg[1]);
  461.   fclose(ofile);
  462. }
  463.  
  464. static long rdf_segbase (long segment) {
  465.     return 0;
  466. }
  467.  
  468. static int rdf_directive (char *directive, char *value, int pass) {
  469.     struct DLLRec r;
  470.     
  471.     if (! strcmp(directive, "library")) {
  472.     if (pass == 1) {
  473.         r.type = 4;
  474.         strcpy(r.libname, value);
  475.         write_dll_rec(&r);
  476.     }
  477.     return 1;
  478.     }
  479.  
  480.     return 0;
  481. }
  482.  
  483. static void rdf_filename (char *inname, char *outname, efunc error) {
  484.   standard_extension(inname,outname,".rdf",error);
  485. }
  486.  
  487. struct ofmt of_rdf = {
  488.   "Relocatable Dynamic Object File Format v1.1",
  489.   "rdf",
  490.   rdf_init,
  491.   rdf_out,
  492.   rdf_deflabel,
  493.   rdf_section_names,
  494.   rdf_segbase,
  495.   rdf_directive,
  496.   rdf_filename,
  497.   rdf_cleanup
  498. };
  499.  
  500. #endif /* OF_RDF */
  501.